#pragma once
#include "Any.hpp"
#include "Log.hpp"

namespace zzz {
class AnyHolder
{
public:
  virtual ~AnyHolder() {
    Clear();
  }

  template<typename T>
  bool Add(T v, const string &name, bool cover=false) {
    if (holder_.find(name)!=holder_.end()) {
      if (cover) {
        Remove(name);
        ZLOG(ZVERBOSE)<<"Duplicated name in AnyHolder: "<<name<<", removed the old one!\n";
      } else {
        ZLOG(ZVERBOSE)<<"Duplicated name in AnyHolder: "<<name<<", refuse to add!\n";
        return false;
      }
    }
    holder_[name]=Any(v);
    return true;
  }

  virtual bool Remove(const string &name) {
    map<string,Any>::iterator mi=holder_.find(name);
    if (mi==holder_.end()) {
      ZLOG(ZERROR)<<"object "<<name<<" is not in ResourceManager\n";
      return false;
    }
    Destroy(mi->second);
    holder_.erase(mi);
    return true;
  }

  virtual void Clear() {
    for (map<string,Any>::iterator mi=holder_.begin();mi!=holder_.end();mi++)
      Destroy(mi->second);
    holder_.clear();
  }

  template<typename T>
  T Get(const string &name) {
    map<string,Any>::iterator mi=holder_.find(name);
    if (mi==holder_.end())
      ZLOG(ZFATAL)<<"Any Holder cannot find: "<<name<<endl;
    return any_cast<T>(mi->second);
  }

  bool IsExist(const string &name) {
    return holder_.find(name) != holder_.end();
  }

  template<typename T>
  bool IsType(const string &name) {
    map<string,Any>::iterator mi=holder_.find(name);
    if (mi==holder_.end()) {
      ZLOG(ZFATAL)<<"Any Holder cannot find: "<<name<<endl;
      return false;  // Will exit before reach this line.
    }
    else
      return mi->second.IsType<T>();
  }

  bool Rename(const string &oldname, const string &newname) {
    map<string,Any>::iterator mi=holder_.find(oldname);
    if (mi == holder_.end()) {
      ZLOG(ZERROR)<<"Cannot find: "<<oldname<<endl;
      return false;
    }
    if (holder_.find(newname)!=holder_.end()) {
      ZLOG(ZERROR)<<"Already existed: "<<newname<<endl;
      return false;
    }
    holder_[newname]=mi->second;
    holder_.erase(oldname);
    return true;
  }

protected:
  virtual void Destroy(Any &v){}
  map<string, Any> holder_;
};
}  // namespace zzz